/*
 * GeoDatabase.h
 *
 *  Created on: 13 Jul 2011
 *      Author: allan
 */

#ifndef GEODATABASE_H_
#define GEODATABASE_H_

// C++ includes
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>
using namespace std;

// Boost includes
#include <boost/optional.hpp>

struct ReactionData
{
	/// The reactant in the reaction
	string reactant;
	
	/// The products in the reaction 
	vector<pair<double,string>> products;
	
	/// The equilibrium constants of the reaction over a set of temperature points (log(K), T)
	vector<pair<double,double>> logK;
};

struct SpeciesData
{
	/// The name of the species
	string name;
	
	/// The name of the phase where the species exists
	string phase;
	
	/// The elemental composition of the species
	vector<pair<double,string>> elemental_composition;
	
	/// The molecular weight of the species
	double molecular_weight;
	
	/// The volumetric weight of the species
	double volumetric_weigth;
	
	/// The radius of the species
	double radius;
};

struct ComplexData
{
	/// The name of the aqueous complex 
	string name;
	
	/// The ionic composition of the aqueous complex 
	vector<pair<double,string>> composition;
};

class GeoDatabase
{
public:
	typedef map<string, ReactionData>
	ReactionSet;
	
	typedef map<string, SpeciesData>
	SpeciesSet;
	
	typedef map<string, ComplexData>
	ComplexSet;
	
	typedef set<string>
	BasisSet;
	
private:
	GeoDatabase();
	
	GeoDatabase(const string& path);
	
public:
	static void
	SetDatabasePath(const string& path);
	
	static const string
	GetDatabasePath();
	
	static const GeoDatabase& 
	GetInstance();
	
	const ReactionSet&
	GetReactionSet() const;
	
	const SpeciesSet&
	GetSpeciesSet() const;
	
	const ComplexSet&
	GetComplexSet() const;
	
	const BasisSet&
	GetBasisSet() const;
	
	const boost::optional<ReactionData>
	FindReaction(const string& reactant) const;
	
	const boost::optional<SpeciesData>
	FindSpecies(const string& species) const;
	
	const boost::optional<ComplexData>
	FindComplex(const string& complex) const;
	
	static const bool
	IsBasis(const string& species);
	
	static const bool
	IsSecondary(const string& species);
	
	static const bool
	IsComplex(const string& species);
	
	static const bool
	IsIonic(const string& species);
	
	static const bool
	IsAqueous(const string& species);
	
	static const bool
	IsGaseous(const string& species);
	
	static const bool
	IsMineral(const string& species);
	
	static const double
	ElectricalCharge(const string& species);
	
	static const double
	ElementAtoms(const string& species, const string& element);
	
	static const double
	MolecularWeight(const string& species);
	
	static const double
	VolumetricWeight(const string& species);
	
private:
	/// The reactions in the database
	ReactionSet reactions;
	
	/// The species in the database
	SpeciesSet species;
	
	/// The aqueous complexes in the database
	ComplexSet complexes;
	
	/// The basis species in the database
	BasisSet basis;
	
	/// The unique instance of a GeoDatabase class
	static std::shared_ptr<GeoDatabase> instance;
	
	/// The path where the database files are located
	static string path;
};

const vector<string>
SpeciateSpecies(const vector<string>& components);

const vector<string>
SpeciateAqueousSpecies(const vector<string>& components);

const vector<string>
SpeciateGaseousSpecies(const vector<string>& components);

const vector<string>
SpeciateMineralSpecies(const vector<string>& components);

const vector<string>
SpeciateBasisSpecies(const vector<string>& components);

const vector<string>
SpeciateSecondarySpecies(const vector<string>& components);

#endif /* GEODATABASE_H_ */
